﻿using System;
using System.Collections.Generic;
using umbraco.cms.businesslogic;

namespace Our.Umbraco.uDbCompare
{
    /// <summary>
    /// uDbCompareCMSNode extends CMSNode to enable it to save data to the umbracoNode table
    /// These are all the configuration settings such as Server Name, Connection String, & Umbraco URL
    ///
    /// Server Name is the name of the root name and has 2 children.
    /// Connection string is the first node that doesn't start with http 
    /// URL is the first node that starts with http
    /// 
    /// TODO: The above logic may have issues with empty text nodes....should be tested
    /// 
    /// Unfortunately, can't find a better way of doing this without either adding more objectTypes (cluttering up the database)
    /// or creating documents, which then appear in umbraco, which we don't want
    /// </summary>
    public class uDbCompareCMSNode : CMSNode
    {
        /// <summary>
        /// The objectType used in the umbracoNode table
        /// </summary>
        private static Guid objectType = new Guid("CB0A3562-E53D-4847-AEC3-72EB7789A398");

        /// <summary>
        /// There are currently 2 children for the uDbCompare node 
        /// Href if found by expecting a http beginning
        /// </summary>
        private enum ChildNodeType
        {
            ConnectionString,
            Href
        }

        /// <summary>
        /// Remove the uDbCompare server node and all child settings
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public static bool Delete(int nodeId)
        {
            if (nodeId > 0)
            {
                var node = new CMSNode(nodeId);
                if (node != null)
                {
                    foreach (CMSNode child in node.GetDescendants())
                    {
                        child.delete();
                    }

                    node.delete();

                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Create a new uDbCompare node with the default options & level
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static CMSNode MakeNew(int userId, string text)
        {
            return MakeNew(-1, userId, 1, text);
        }

        /// <summary>
        /// Create a new uDbCompare node 
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="userId"></param>
        /// <param name="level"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static CMSNode MakeNew(int parentId, int userId, int level, string text)
        {
            // Create the new DbCompare Node
            CMSNode node = CMSNode.MakeNew(parentId, objectType, userId, level, text, Guid.NewGuid());
            CMSNode settingsNode = CMSNode.MakeNew(node.Id, objectType, userId, level + 1, text, Guid.NewGuid());
            CMSNode hrefNode = CMSNode.MakeNew(node.Id, objectType, userId, level + 1, "http://", Guid.NewGuid());

            return node;
        }

        /// <summary>
        /// Get the name of the connection (e.g. the name of the node)
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public static string GetConnectionName(int nodeId)
        {
            CMSNode node = new CMSNode(nodeId);
            return node.Text;
        }

        /// <summary>
        /// Get the saved connection string of the umbraco instance for the parent node id
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public static string GetConnectionString(int nodeId)
        {
            CMSNode node = GetChildNode(nodeId, ChildNodeType.ConnectionString);
            if (node != null)
                return node.Text;
            else
                return string.Empty;
        }

        /// <summary>
        /// Get the saved Href of the umbraco instance for the parent node id
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public static string GetHref(int nodeId)
        {
            CMSNode node = GetChildNode(nodeId, ChildNodeType.Href);
            if (node != null)
                return node.Text;
            else
                return string.Empty;
        }

        /// <summary>
        /// Get the saved Href of the umbraco instance for the parent node id, but make sure its a valid url
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public static string GetValidHref(int nodeId)
        {
            string baseUrl = GetHref(SessionVars.NodeId);
            // If the base url was not set, or is not a uri, then return empty string
            Uri uri = null;
            if (string.IsNullOrEmpty(baseUrl) || !System.Uri.TryCreate(baseUrl, UriKind.RelativeOrAbsolute, out uri))
                return string.Empty;
            return baseUrl;
        }

        /// <summary>
        /// Find the child setting node
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="nodeType"></param>
        /// <returns></returns>
        private static CMSNode GetChildNode(int nodeId, ChildNodeType nodeType)
        {
            if (nodeId > 0)
            {
                CMSNode node = new CMSNode(nodeId);
                foreach (var child in node.GetDescendants())
                {
                    var childNode = child as CMSNode;
                    if (childNode != null)
                    {
                        switch (nodeType)
                        {
                            case ChildNodeType.ConnectionString:
                                if (!childNode.Text.StartsWith("http"))
                                    return childNode;
                                break;
                            case ChildNodeType.Href:
                                if (childNode.Text.StartsWith("http"))
                                    return childNode;
                                break;
                        }
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Save the connection name (e.g. server name)
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="connectionName"></param>
        public static void SaveConnectionName(int nodeId, string connectionName)
        {
            CMSNode node = new CMSNode(nodeId);
            node.Text = connectionName;
        }

        /// <summary>
        /// Save the connection string of the umbraco instance for the parent node id
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="connectionString"></param>
        public static void SaveConnectionString(int nodeId, string connectionString)
        {
            bool found = false;
            if (nodeId > 0)
            {
                CMSNode node = GetChildNode(nodeId, ChildNodeType.ConnectionString);
                if (node != null)
                {
                    node.Text = connectionString;
                    found = true;
                }

                if (!found)
                {
                    CMSNode settingsNode = CMSNode.MakeNew(nodeId, objectType, 0, 2, connectionString, Guid.NewGuid());
                }
            }
        }

        /// <summary>
        /// Save the umbraco instance url for the parent node id
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="href"></param>
        public static void SaveHref(int nodeId, string href)
        {
            bool found = false;
            if (nodeId > 0)
            {
                CMSNode node = GetChildNode(nodeId, ChildNodeType.Href);
                if (node != null)
                {
                    node.Text = href;
                    found = true;
                }

                if (!found)
                {
                    CMSNode hrefNode = CMSNode.MakeNew(nodeId, objectType, 0, 2, href, Guid.NewGuid());
                }
            }
        }

        /// <summary>
        /// Get a list of all the server names
        /// </summary>
        /// <returns></returns>
        public static List<CMSNode> GetAllNodes()
        {
            List<CMSNode> allNodes = new List<CMSNode>();
            int[] ids = CMSNode.getAllUniqueNodeIdsFromObjectType(objectType);
            foreach (var id in ids)
            {
                var node = new CMSNode(id);
                if (node.Level == 1)
                    allNodes.Add(node);
            }

            return allNodes;
        }
    }
}